#include<system.h>
#include "network.h"
#include "post.h"
#include "interrupt.h"


#define FREE 1
#define BUSY 0
#define maxLock 500
#define maxCV 1000
#define maxMV 1000
#define serverid 0

struct lockEntry{
	char name[10];
	int ownerHost;
	int ownerMailbox;
	int status;
	List *waitQueueListHost;
	List *waitQueueListmailbox;
	int waitcount;
};

struct CVEntry{
	char name[10];
	int lockid;
	int count;
	int ownerHost;
	List * waitQueueListHost;
	List * waitQueueListmailbox;
};

struct MVEntry{
	char name[10];
	int* value;			//MV value
	int use; //may be useful
};

BitMap* lockMap;
BitMap* cvMap;
BitMap* mvMap;
/*
Lock lockMapLock("lml");
Lock cvMapLock("cml");
Lock mvMapLock("mml");
*/

lockEntry RPCLock[maxLock];
CVEntry RPCCV[maxCV];
MVEntry RPCMV[maxMV];

void createlock(int host,int mfrom,char * lockname){
	int lockID=-1;
	char response[MaxMailSize];
    PacketHeader outPktHdr, inPktHdr;
    MailHeader outMailHdr, inMailHdr;

	for(int i=0;i<maxLock;i++)
		if(strcmp(RPCLock[i].name,lockname)==0){
			lockID=i;
			break;	
		}
	if(lockID==-1){	
		lockID = lockMap->Find();
		strcpy(RPCLock[lockID].name,lockname);
	}
	
	sprintf(response,"%d",lockID);

	outPktHdr.to = host;
	outMailHdr.from = 1;
	outMailHdr.to = mfrom;
	outMailHdr.length = strlen(response)+1;
	printf("Send %s to %d, box %d\n", response,outPktHdr.to,outMailHdr.to);
	postOffice->Send(outPktHdr,outMailHdr,response);

	return;
}

void destroylock(int lockid,int host,int mailbox){
	
    PacketHeader outPktHdr, inPktHdr;
    MailHeader outMailHdr, inMailHdr;
	char response[5];

	if(lockMap->Test(lockid)==FALSE)	//lock is not exsitent
		strcpy(response,"F1");
	else if(RPCLock[lockid].status==BUSY)	//lock is busy	
		strcpy(response,"F2");
//	else if(RPCLock[lockid].ownerHost!=host)	//lock belongs to other host
//		strcpy(response,"F3");
	else{
		lockMap->Clear(lockid);
		RPCLock[lockid].ownerHost = -1;
		RPCLock[lockid].ownerMailbox = -1;	
		RPCLock[lockid].waitcount=0;
		strcpy(RPCLock[lockid].name,"");
		strcpy(response,"S");
	}
	
	outPktHdr.to = host;
	outMailHdr.from = 1;
	outMailHdr.to =mailbox;
	outMailHdr.length = strlen(response)+1;

	postOffice->Send(outPktHdr,outMailHdr,response);

	return;

}

void acquirelock(int lockid,int host,int mailbox){

	PacketHeader outPktHdr, inPktHdr;
	MailHeader outMailHdr, inMailHdr;
	char response[5];

	if(lockMap->Test(lockid)==FALSE)	//lock is not exsitent
		strcpy(response,"F4");
//	else if(RPCLock[lockid].ownerHost!=host)
//		strcpy(response,"F5");
	else if(RPCLock[lockid].ownerMailbox==mailbox&&RPCLock[lockid].ownerHost==host)
		strcpy(response,"S");
	else if(RPCLock[lockid].status==FREE){
		RPCLock[lockid].status=BUSY;
		RPCLock[lockid].ownerHost=host;
		RPCLock[lockid].ownerMailbox=mailbox;		
		strcpy(response,"S");
	}
	else{
		RPCLock[lockid].waitQueueListHost->Append((void *)host);
		RPCLock[lockid].waitQueueListmailbox->Append((void *)mailbox);
		RPCLock[lockid].waitcount++;
		return;
	}
	
	outPktHdr.to = host;
	outMailHdr.from = 1;
	outMailHdr.to =mailbox;
	outMailHdr.length = strlen(response)+1;
	postOffice->Send(outPktHdr,outMailHdr,response);

	return;
	
}


void releaselock(int lockid,int host,int mailbox){
	PacketHeader outPktHdr, inPktHdr;
	MailHeader outMailHdr, inMailHdr;
	char response[5];

	if(lockMap->Test(lockid)==FALSE)	//lock is not exsitent
		strcpy(response,"F4");
	else if(RPCLock[lockid].ownerHost!=host)
		strcpy(response,"F6");
	else if(RPCLock[lockid].ownerMailbox!=mailbox)
		strcpy(response,"F7");
	else if(RPCLock[lockid].waitcount>0){
		RPCLock[lockid].ownerHost=(int)RPCLock[lockid].waitQueueListHost->Remove();
		RPCLock[lockid].ownerMailbox=(int)RPCLock[lockid].waitQueueListmailbox->Remove();
		RPCLock[lockid].waitcount--;

		strcpy(response,"S");
		outPktHdr.to = RPCLock[lockid].ownerHost;
		outMailHdr.from = 1;
		outMailHdr.to = RPCLock[lockid].ownerMailbox;
		outMailHdr.length = strlen(response)+1;
		postOffice->Send(outPktHdr,outMailHdr,response);
		//printf(" send %s to %d , %d.\n", response,RPCLock[lockid].ownerHost,RPCLock[lockid].ownerMailbox);
	}
	else{
		RPCLock[lockid].status=FREE;
		RPCLock[lockid].ownerHost=-1;
		RPCLock[lockid].ownerMailbox=-1;
		strcpy(response,"S");
	}

	outPktHdr.to = host;
	outMailHdr.from = 1;
	outMailHdr.to = mailbox;
	outMailHdr.length = strlen(response)+1;
	postOffice->Send(outPktHdr,outMailHdr,response);		

	return;

}

void createcv(int host,int mailbox,char* name){
	int cvID=-1;
	char response[MaxMailSize];
    PacketHeader outPktHdr, inPktHdr;
    MailHeader outMailHdr, inMailHdr;

	
	for(int i=0;i<maxLock;i++)
		if(strcmp(RPCCV[i].name,name)==0){
			cvID=i;
			break;	
		}
	if(cvID==-1){	
		cvID = cvMap->Find();
		strcpy(RPCCV[cvID].name,name);
	}
	
	sprintf(response,"%d",cvID);

	outPktHdr.to = host;
	outMailHdr.from = 1;
	outMailHdr.to = mailbox;
	outMailHdr.length = strlen(response)+1;
	printf("Send %s to %d, box %d\n", response,outPktHdr.to,outMailHdr.to);
	postOffice->Send(outPktHdr,outMailHdr,response);

	return;
}

void destroycv(int cvid,int host,int mailbox){
	
    PacketHeader outPktHdr, inPktHdr;
    MailHeader outMailHdr, inMailHdr;
	char response[5];

	if(cvMap->Test(cvid)==FALSE)	//cv is not exsitent
		strcpy(response,"F8");
//	else if(RPCCV[cvid].ownerHost!=host)	//cv belongs to other host
//		strcpy(response,"F9");
	else{
		cvMap->Clear(cvid);
		//RPCCV[cvid].ownerHost = -1;
		//RPCCV[cvid].ownerMailbox = -1;	
		//RPCCV[cvid].waitQueueIndex=0;
		//RPCCV[cvid].signalQueueIndex=0;
		RPCCV[cvid].count=0;
		strcpy(RPCCV[cvid].name,"");
		strcpy(response,"S");
	}
	
	outPktHdr.to = host;
	outMailHdr.from = 1;
	outMailHdr.to =mailbox;
	outMailHdr.length = strlen(response)+1;

	postOffice->Send(outPktHdr,outMailHdr,response);

	return;

}

void test(int host,int mailbox,int cvid, int lockid){
	
    PacketHeader outPktHdr, inPktHdr;
    MailHeader outMailHdr, inMailHdr;
	char response[5];

	if(cvMap->Test(cvid)==FALSE||lockMap->Test(lockid)==FALSE)	//cv&lock is not exsitent
		strcpy(response,"F8");
	else if(RPCLock[lockid].ownerMailbox!=mailbox||RPCLock[lockid].ownerHost!=host)//does not owen the lock
		strcpy(response,"FA");
	else if(RPCCV[cvid].lockid!=lockid&&RPCCV[cvid].lockid!=-1)
		strcpy(response,"FB");
	else 
		strcpy(response,"S");
	
	outPktHdr.to = host;
	outMailHdr.from = 1;
	outMailHdr.to = mailbox;
	outMailHdr.length = strlen(response)+1;

	postOffice->Send(outPktHdr,outMailHdr,response);

	return;
	
}

void wait(int host,int mailbox,int cvid, int lockid){
	
    PacketHeader outPktHdr, inPktHdr;
    MailHeader outMailHdr, inMailHdr;
	char response[5];

	if(cvMap->Test(cvid)==FALSE||lockMap->Test(lockid)==FALSE)	//cv&lock is not exsitent
		strcpy(response,"F8");
//	else if(RPCCV[cvid].ownerHost!=host)	//cv belongs to other host
//		strcpy(response,"F9");
	else if(RPCLock[lockid].ownerMailbox!=mailbox||RPCLock[lockid].ownerHost!=host)//does not owen the lock
		strcpy(response,"FA");
	else if(RPCCV[cvid].lockid!=lockid&&RPCCV[cvid].lockid!=-1)
		strcpy(response,"FB");
	else {
		if(RPCCV[cvid].lockid==-1)
			RPCCV[cvid].lockid=lockid;
		RPCCV[cvid].waitQueueListHost->Append((void *)host);
		RPCCV[cvid].waitQueueListmailbox->Append((void *)mailbox);
		return;
	}
	
	outPktHdr.to = host;
	outMailHdr.from = 1;
	outMailHdr.to = mailbox;
	outMailHdr.length = strlen(response)+1;

	postOffice->Send(outPktHdr,outMailHdr,response);

	return;
	
}

void signal(int host,int mailbox,int cvid, int lockid){
	
    PacketHeader outPktHdr, inPktHdr;
    MailHeader outMailHdr, inMailHdr;
	char response[5];
	int mailbox_t;
	int host_t;

	if(cvMap->Test(cvid)==FALSE||lockMap->Test(lockid)==FALSE)	//cv&lock is not exsitent
		strcpy(response,"F8");
//	else if(RPCCV[cvid].ownerHost!=host)	//cv belongs to other host
//		strcpy(response,"F9");
	else if(RPCLock[lockid].ownerMailbox!=mailbox||RPCLock[lockid].ownerHost!=host)//does not owen the lock
		strcpy(response,"FA");
	else if(RPCCV[cvid].lockid!=lockid&&RPCCV[cvid].lockid!=-1)
		strcpy(response,"FB");
	else if(RPCCV[cvid].waitQueueListHost->IsEmpty()==TRUE)
		strcpy(response,"FC");
	else{
		host_t=(int)RPCCV[cvid].waitQueueListHost->Remove();
		mailbox_t=(int)RPCCV[cvid].waitQueueListmailbox->Remove();
		strcpy(response,"S");

		outPktHdr.to=host_t;
		outMailHdr.from = 1;
		outMailHdr.to = mailbox_t;
		outMailHdr.length = strlen(response)+1;
		
		postOffice->Send(outPktHdr,outMailHdr,response);

		if(RPCCV[cvid].waitQueueListHost->IsEmpty()==TRUE)
			RPCCV[cvid].lockid=-1;			
	}
	
	outPktHdr.to = host;
	outMailHdr.from = 1;
	outMailHdr.to = mailbox;
	outMailHdr.length = strlen(response)+1;

	postOffice->Send(outPktHdr,outMailHdr,response);

	return;
	
}

void broadcast(int host,int mailbox,int cvid, int lockid){
    PacketHeader outPktHdr, inPktHdr;
    MailHeader outMailHdr, inMailHdr;
	char response[5];
	int mailbox_t;
	int host_t;

	if(cvMap->Test(cvid)==FALSE)	//cv is not exsitent
		strcpy(response,"F8");
//	else if(RPCCV[cvid].ownerHost!=host)	//cv belongs to other host
//		strcpy(response,"F9");
	else if(RPCLock[lockid].ownerMailbox!=mailbox&&RPCLock[lockid].ownerHost!=host)//does not owen the lock
		strcpy(response,"FA");
	else if(RPCCV[cvid].lockid!=lockid&&RPCCV[cvid].lockid!=-1)
		strcpy(response,"FB");
	else if(RPCCV[cvid].waitQueueListHost->IsEmpty()==TRUE)
		strcpy(response,"FC");
	else{
		
		strcpy(response,"S");
		while(RPCCV[cvid].waitQueueListHost->IsEmpty()!=TRUE){
			host_t=(int)RPCCV[cvid].waitQueueListHost->Remove();
			mailbox_t=(int)RPCCV[cvid].waitQueueListmailbox->Remove();

			outPktHdr.to = host_t;
			outMailHdr.from = 1;
			outMailHdr.to = mailbox_t;
			outMailHdr.length = strlen(response)+1;
		
			postOffice->Send(outPktHdr,outMailHdr,response);

			if(RPCCV[cvid].waitQueueListHost->IsEmpty()==TRUE)
				RPCCV[cvid].lockid=-1;
			}
		}
	
	outPktHdr.to = host;
	outMailHdr.from = 1;
	outMailHdr.to = mailbox;
	outMailHdr.length = strlen(response)+1;

	postOffice->Send(outPktHdr,outMailHdr,response);

	return;

}

void createmv(int host,int mailbox,char* name,int arraysize){
	int mvID=-1;
	char response[MaxMailSize];
    PacketHeader outPktHdr, inPktHdr;
    MailHeader outMailHdr, inMailHdr;

	//consider the conflict in the same name with different arraysize
	for(int i=0;i<maxLock;i++)
		if(strcmp(RPCMV[i].name,name)==0){
			mvID=i;
			break;	
		}
	if(mvID==-1){	
		mvID = mvMap->Find();
		strcpy(RPCMV[mvID].name,name);
		RPCMV[mvID].value = new int[arraysize];
		for(int i=0;i<arraysize;i++)
			RPCMV[mvID].value[i]=0;
	}
	
	sprintf(response,"%d",mvID);

	outPktHdr.to = host;
	outMailHdr.from = 1;
	outMailHdr.to = mailbox;
	outMailHdr.length = strlen(response)+1;
	printf("Send %s to %d, box %d\n", response,outPktHdr.to,outMailHdr.to);
	postOffice->Send(outPktHdr,outMailHdr,response);

	return;
}

void destroymv(int mvid,int host,int mailbox){
	
    PacketHeader outPktHdr, inPktHdr;
    MailHeader outMailHdr, inMailHdr;
	char response[5];

	if(mvMap->Test(mvid)==FALSE)	//mv is not exsitent
		strcpy(response,"F8");
	else{
		mvMap->Clear(mvid);
		strcpy(RPCMV[mvid].name,"");
		strcpy(response,"S");
	}
	
	outPktHdr.to = host;
	outMailHdr.from = 1;
	outMailHdr.to =mailbox;
	outMailHdr.length = strlen(response)+1;

	postOffice->Send(outPktHdr,outMailHdr,response);

	return;

}

void setmv(int host, int mailbox,int mvid,int index,int value){
    PacketHeader outPktHdr, inPktHdr;
    MailHeader outMailHdr, inMailHdr;
	char response[5];

	if(mvMap->Test(mvid)==FALSE)	//mv is not exsitent
		strcpy(response,"F8");
	else{
		RPCMV[mvid].value[index]=value;
		strcpy(response,"S");
	}

	outPktHdr.to = host;
	outMailHdr.from = 1;
	outMailHdr.to =mailbox;
	outMailHdr.length = strlen(response)+1;

	postOffice->Send(outPktHdr,outMailHdr,response);

	return;

}

void getmv(int host, int mailbox,int mvid,int index){
    PacketHeader outPktHdr, inPktHdr;
    MailHeader outMailHdr, inMailHdr;
	char response[5];
	int value;

	if(mvMap->Test(mvid)==FALSE)	//mv is not exsitent
		strcpy(response,"F8");
	else{
		value=RPCMV[mvid].value[index];
		sprintf(response,"%d",value);
	}

	outPktHdr.to = host;
	outMailHdr.from = 1;
	outMailHdr.to =mailbox;
	outMailHdr.length = strlen(response)+1;

	postOffice->Send(outPktHdr,outMailHdr,response);

	return;

}

void initialize(){
	int i;
	int j;

	lockMap = new BitMap(maxLock);
	cvMap = new BitMap(maxCV);
	mvMap = new BitMap(maxMV);
	
	for(i=0;i<maxLock;i++){
		RPCLock[i].ownerHost=-1;
		RPCLock[i].ownerMailbox= -1;
		RPCLock[i].status=FREE;
		RPCLock[i].waitcount=0;
		RPCLock[i].waitQueueListHost= new List;
		RPCLock[i].waitQueueListmailbox = new List;
	}

	for(i=0;i<maxCV;i++){
		//RPCCV[i].ownerHost=-1;
		RPCCV[i].lockid=-1;
		RPCCV[i].count=0;
		//RPCCV[i].signalQueueIndex=0;
		//RPCCV[i].waitQueueIndex=0;
		RPCCV[i].waitQueueListHost = new List;
		RPCCV[i].waitQueueListmailbox= new List;

	}


}

void netserver(){
	
    PacketHeader outPktHdr, inPktHdr;
    MailHeader outMailHdr, inMailHdr;
    char request[MaxMailSize];
	char data[MaxMailSize];
	int int_response;
	int int_data;
	int conditionid,lockid;
	int stopFlag=0;
	char char_cid[4], char_lid[4];
	char response[MaxMailSize];
	char name[10];
	
	initialize();

	while(true){

		//Get the request from client
		postOffice->Receive(0,&inPktHdr,&inMailHdr,request);
		printf("Got %s from %d, box %d\n", request, inPktHdr.from,inMailHdr.from);
		fflush(stdout);

		//Parse the msg
			switch(request[0]){
				case 'L':
					if(request[1]=='C'){
						for(int i=0;i<10;i++)
							request[i]=request[i+2];
						createlock(inPktHdr.from,inMailHdr.from,request);
					}
					else if(request[1]=='D'){	
						for(int i=0;i<7;i++)
							request[i]=request[i+2];
						int_data = atoi(request);
						destroylock(int_data,inPktHdr.from,inMailHdr.from);
					}
					break;
				case 'A':
					for(int i=0;i<7;i++)
						request[i]=request[i+1];
					int_data = atoi(request);
					acquirelock(int_data,inPktHdr.from,inMailHdr.from);
					break;
				case 'R':
					for(int i=0;i<7;i++)
						request[i]=request[i+1];
					int_data = atoi(request);
					releaselock(int_data,inPktHdr.from,inMailHdr.from);
					break;
				case 'C':
					if(request[1]=='C'){
						for(int i=0;i<10;i++)
							request[i]=request[i+2];
						createcv(inPktHdr.from,inMailHdr.from,request);
					}
					else if(request[1]=='D'){				
						for(int i=0;i<7;i++)
							request[i]=request[i+2];
						int_data = atoi(request);
						destroycv(int_data,inPktHdr.from,inMailHdr.from);
					}
					break;			
				case 'T':
					for(int i=0;i<3;i++){
						char_cid[i]=request[i+1];
						char_lid[i]=request[i+5];
					}
					char_cid[3]='\0';
					char_lid[3]='\0';
					conditionid=atoi(char_cid);
					lockid=atoi(char_lid);
					test(inPktHdr.from,inMailHdr.from,conditionid,lockid);
					break;
				case 'W':
					for(int i=0;i<3;i++){
						char_cid[i]=request[i+1];
						char_lid[i]=request[i+5];
					}
					char_cid[3]='\0';
					char_lid[3]='\0';
					conditionid=atoi(char_cid);
					lockid=atoi(char_lid);
					wait(inPktHdr.from,inMailHdr.from,conditionid,lockid);
					break;
				case 'S':
					for(int i=0;i<3;i++){
						char_cid[i]=request[i+1];
						char_lid[i]=request[i+5];
					}
					char_cid[3]='\0';
					char_lid[3]='\0';
					conditionid=atoi(char_cid);
					lockid=atoi(char_lid);
					signal(inPktHdr.from,inMailHdr.from,conditionid,lockid);
					break;
				case 'B':
					for(int i=0;i<3;i++){
						char_cid[i]=request[i+1];
						char_lid[i]=request[i+5];
					}
					char_cid[3]='\0';
					char_lid[3]='\0';
					conditionid=atoi(char_cid);
					lockid=atoi(char_lid);
					broadcast(inPktHdr.from,inMailHdr.from,conditionid,lockid);
					break;		
				case 'M':
					if(request[1]=='C'){
						for(int i=0;i<10;i++)
							name[i]=request[i+2];
						name[10]='\0';
						for(int i=0;i<4;i++)
							request[i]=request[i+12];
						request[4]='\0';
						int_data=atoi(request);
						createmv(inPktHdr.from,inMailHdr.from,name,int_data);
					}
					else if(request[1]=='D'){				
					for(int i=0;i<7;i++)
						request[i]=request[i+2];
					int_data = atoi(request);
					destroymv(int_data,inPktHdr.from,inMailHdr.from);
					}
					else if(request[1]=='S'){	
					int value;
					int index;
					int mv;
					char translateMv[4];
					char translateindex[4];
					char translatevalue[6];
					for(int i=0;i<3;i++){
						translateMv[i]=request[i+2];
						translateindex[i]=request[i+5];						
					}
					translateMv[3]='\0';
					translateindex[3]='\0';
					for(int i=0;i<5;i++)
						translatevalue[i]=request[i+8];
					translatevalue[5]='\0';
					mv = atoi(translateMv);
					index = atoi(translateindex);
					value = atoi(translatevalue);
					setmv(inPktHdr.from,inMailHdr.from,mv,index,value);
					}
					else if(request[1]='G'){
					int mv;
					int index;
					char translateMv[4];
					char translateindex[4];
					for(int i=0;i<3;i++){
						translateMv[i]=request[i+2];
						translateindex[i]=request[i+5];						
					}
					translateMv[3]='\0';
					translateindex[3]='\0';
					mv = atoi(translateMv);
					index = atoi(translateindex);
					getmv(inPktHdr.from,inMailHdr.from,mv,index);
					}
					break;
				case 'K':
					stopFlag=1;
					break;
				default:
					printf("error request.\n");	
			}
			
			if(stopFlag==1)
				break;
	}

	printf("**************************server end*********************************\n");
	interrupt->Halt();
}

